//
// Created by suzhen on 16-11-14.
//

#ifndef OKREDIS_OKREDISTOOLS_H
#define OKREDIS_OKREDISTOOLS_H

#include "OkRedisCore.h"
#include "OkRedisReply.h"
#include <functional>

namespace NoSQL {

    /**
     * OKRedis入口类
     * 
     */
    class OkRedis {

    public:
        template<typename T>
        using OkRedisReplyContentFuture  = Orion::V2::Future<OkRedisReplyContent<T>>;

        template<typename T>
        using OkRedisReplyContentPromise = Orion::V2::Promise<OkRedisReplyContent<T>>;

    public:
        OkRedis(const std::string &ip, int port);

        Orion::V2::Future<bool> start();

        Orion::V2::Future<bool> shutdown();

        virtual ~OkRedis();

    public:
        OkRedisReplyContentFuture<OkRedisBoolType>
        set(const std::string &key, const std::string &value);

        OkRedisReplyContentFuture<OkRedisStringType>
        get(const std::string &key);

        OkRedisReplyContentFuture<OkRedisBoolType>
        hset(const std::string &domain, const std::string &key, const std::string &value);

        OkRedisReplyContentFuture<OkRedisStringType>
        hget(const std::string &domain, const std::string &key);

        OkRedisReplyContentFuture<OkRedisBoolType>
        setWithTTL(const std::string &key, const std::string &value, int ttlSeconds);

        OkRedisReplyContentFuture<OkRedisBoolType>
        expire(const std::string &key, int ttlSeconds);

        OkRedisReplyContentFuture<OkRedisBoolType>
        exists(const std::string &key);

        OkRedisReplyContentFuture<OkRedisBoolType>
        del(const std::string &key);

        OkRedisReplyContentFuture<OkRedisBoolType>
        hdel(const std::string &domain, const std::string &key);

        OkRedisReplyContentFuture<OkRedisMapType>
        hgetall(const std::string &domain);

        OkRedisReplyContentFuture<OkRedisIntType>
        incr(const std::string &key);

        OkRedisReplyContentFuture<OkRedisIntType>
        incrBy(const std::string &key, int num);

    private:
        OkRedisCore *okRedisCore_;

    private:

        template<typename OkRedisTp,
                typename F = OkRedisReplyContentFuture<OkRedisTp>,
                typename P = OkRedisReplyContentPromise<OkRedisTp>
        >
        F cmd2Redis(const std::string &cmd) {
            std::shared_ptr<P> sp(new P);
            F f = sp->getFuture();
            if (okRedisCore_->isClosed()) {
                RawRedisReply nullRpy;
                OkRedisReplyType rpt(nullRpy);
                sp->setValue(OkRedisReplyContent<OkRedisTp>(rpt, nullRpy));
                return f;
            }
            okRedisCore_->executeAsyncCmd(
                    cmd.c_str(),
                    [sp](RawRedisReply &r)
                            mutable {
                        OkRedisReplyType rpt(r);
                        OkRedisReplyContent<OkRedisTp> cnt = OkRedisReplyContent<OkRedisTp>(rpt, r);
                        sp->setValue(std::move(cnt));
                    });
            return f;
        }
    };

}

#endif //OKREDIS_OKREDISTOOLS_H
